package com.hanserwei.han_picture.service.seviceImpl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hanserwei.han_picture.constant.SpaceUserPermissionConstant;
import com.hanserwei.han_picture.domain.entity.po.Picture;
import com.hanserwei.han_picture.domain.entity.po.Space;
import com.hanserwei.han_picture.domain.entity.po.SpaceUser;
import com.hanserwei.han_picture.domain.entity.po.User;
import com.hanserwei.han_picture.domain.entity.vo.*;
import com.hanserwei.han_picture.domain.exception.ApiException;
import com.hanserwei.han_picture.domain.file.UploadPictureResult;
import com.hanserwei.han_picture.domain.request.picture.*;
import com.hanserwei.han_picture.domain.request.picture.AlibabaPictureStyleRegenRequest.Input;
import com.hanserwei.han_picture.enums.PictureReviewStatusEnum;
import com.hanserwei.han_picture.enums.ResponseCodeEnum;
import com.hanserwei.han_picture.enums.UserRoleEnum;
import com.hanserwei.han_picture.manager.RedisManager;
import com.hanserwei.han_picture.manager.auth.SpaceUserAuthManager;
import com.hanserwei.han_picture.manager.auth.StpKit;
import com.hanserwei.han_picture.manager.uploadtemplate.FilePictureUpload;
import com.hanserwei.han_picture.manager.uploadtemplate.PictureUploadTemplate;
import com.hanserwei.han_picture.manager.uploadtemplate.URLPictureUpload;
import com.hanserwei.han_picture.mapper.PictureMapper;
import com.hanserwei.han_picture.service.*;
import com.hanserwei.han_picture.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.awt.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture> implements PictureService {

    private static final String API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image-generation/generation";
    private final UserService userService;
    private final RedisManager redisManager;
    private final FilePictureUpload filePictureUpload;
    private final URLPictureUpload urlPictureUpload;
    private final AsyncAiProcessService asyncAiProcessService;
    private final CacheInvalidationService cacheInvalidationService;
    private final SpaceService spaceService;
    private final TransactionTemplate transactionTemplate;
    private final PictureMapper pictureMapper;
    private final ObjectMapper objectMapper;
    private final SpaceUserAuthManager spaceUserAuthManager;
    private final SpaceUserService spaceUserService;
    @Value("${dashscope.api.key}")
    private String dashScopeApiKey;

    /**
     * 打印API请求失败的日志信息
     *
     * @param httpResponse HTTP响应对象
     */
    private static void printLog(HttpResponse httpResponse) {
        log.error("API请求失败，状态码: {}", httpResponse.getStatus());
        log.error("错误信息: {}", httpResponse.body());
    }

    /**
     * 使用DashScope API查询图像风格重绘任务状态
     *
     * @param taskId 任务ID
     * @return 响应实体类对象
     */
    @Override
    public PictureStyleRegenTaskVO queryTaskStatus(String taskId) {
        // 构建请求URL
        String apiUrl = "https://dashscope.aliyuncs.com/api/v1/tasks/" + taskId;

        try {
            // 发送GET请求
            try (HttpResponse httpResponse = HttpRequest.get(apiUrl)
                    .header("Authorization", "Bearer " + this.dashScopeApiKey)
                    .execute()) {

                // 检查响应状态码
                if (httpResponse.isOk()) {
                    return objectMapper.readValue(httpResponse.body(), PictureStyleRegenTaskVO.class);
                } else {
                    printLog(httpResponse);
                    throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "API请求失败" + httpResponse.body() + httpResponse.body());
                }
            }
        } catch (Exception e) {
            log.error("调用DashScope API失败", e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "调用DashScope API失败");
        }
    }

    /**
     * 使用请求实例类调用DashScope API进行图像风格重绘
     *
     * @param request 请求实例对象
     * @return 响应实体类对象
     */
    @Override
    public PictureStyleRegenVO generateImage(PictureStyleRegenRequest request) {
        if (request.getId() == null) {
            throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        }
        try {
            // 使用 Jackson ObjectMapper 将请求对象序列化为 JSON 字符串
            AlibabaPictureStyleRegenRequest alibabaPictureStyleRegenRequest = new AlibabaPictureStyleRegenRequest();
            String imageUrl = request.getImageUrl();
            int styleIndex = request.getStyleIndex();
            alibabaPictureStyleRegenRequest.setInput(new Input(imageUrl, styleIndex));
            String jsonBody = objectMapper.writeValueAsString(alibabaPictureStyleRegenRequest);

            // 发送POST请求
            try (HttpResponse httpResponse = HttpRequest.post(API_URL)
                    .header("X-DashScope-Async", "enable")
                    .header("Authorization", "Bearer " + this.dashScopeApiKey)
                    .header("Content-Type", "application/json")
                    .body(jsonBody)
                    .execute()) {

                // 检查响应状态码
                if (httpResponse.isOk()) {
                    return objectMapper.readValue(httpResponse.body(), PictureStyleRegenVO.class);
                } else {
                    printLog(httpResponse);
                    throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "API请求失败" + httpResponse.body() + httpResponse.body());
                }
            }

        } catch (Exception e) {
            log.error("调用DashScope API失败", e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "调用DashScope API失败");
        }
    }

    /**
     * 删除图片
     *
     * @param pictureId 图片id
     * @param loginUser 登录用户
     * @return boolean 删除结果
     */
    @Override
    public boolean deletePicture(long pictureId, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "权限不足");
        ThrowUtils.throwIf(pictureId <= 0, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        // 查询图片是否存在
        Picture oldPicture = this.getById(pictureId);
        ThrowUtils.throwIf(oldPicture == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "图片不存在");
        // 判断权限
        // checkPictureAuth(oldPicture, loginUser);
        // 删除图片
        transactionTemplate.execute(status -> {
            String oldPictureTags = oldPicture.getTags();
            boolean removed = this.removeById(pictureId);
            ThrowUtils.throwIf(!removed, ResponseCodeEnum.SYSTEM_ERROR, "删除图片失败");
            // 清除Redis标签缓存
            List<String> tagList = JSONUtil.toList(oldPictureTags, String.class);
            redisManager.decrementTagsScore(tagList);
            if (oldPicture.getSpaceId() != null) {
                boolean updated = spaceService.lambdaUpdate()
                        .eq(Space::getId, oldPicture.getSpaceId())
                        .setSql("total_size = total_size - " + oldPicture.getPicSize())
                        .setSql("total_count = total_count - 1")
                        .update();
                ThrowUtils.throwIf(!updated, ResponseCodeEnum.SYSTEM_ERROR, "更新空间失败");
            }
            return true;
        });
        cacheInvalidationService.invalidatePictureListCache();
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean editPictureByBatch(PictureEditByBatchRequest request, User loginUser) {
        // 1. 参数校验
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED);
        List<Long> pictureIdList = request.getPictureIdList();
        Long spaceId = request.getSpaceId();
        String category = request.getCategory();
        List<String> tags = request.getTags();
        String nameRule = request.getNameRule();
        ThrowUtils.throwIf(CollUtil.isEmpty(pictureIdList), ResponseCodeEnum.INVALID_PARAMETER);
        ThrowUtils.throwIf(spaceId == null, ResponseCodeEnum.INVALID_PARAMETER);
        // 2. 空间权限校验
        Space space = spaceService.getById(spaceId);
        ThrowUtils.throwIf(space == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "空间不存在");
        // 3. 查询指定字段的图片
        List<Picture> pictureList = this.lambdaQuery().select(Picture::getId, Picture::getSpaceId)
                .eq(Picture::getSpaceId, spaceId)
                .in(Picture::getId, pictureIdList)
                .list();
        if (CollUtil.isEmpty(pictureList)) {
            return false;
        }
        // 4. 批量更新分类和标签
        pictureList.forEach(picture -> {
            picture.setCategory(category);
            picture.setTags(JSONUtil.toJsonStr(tags));
        });
        // 5. 批量重命名(封装为方法)
        this.fillPictureWithNameRule(pictureList, nameRule);
        // 6. 数据库批量操作
        boolean updated = this.updateBatchById(pictureList);
        ThrowUtils.throwIf(!updated, ResponseCodeEnum.SYSTEM_ERROR, "更新图片失败！");
        return true;
    }

    /**
     * 批量操作图片名称(规则: 图片{序号})
     *
     * @param pictureList 图片列表
     * @param nameRule    图片名称规则
     */
    private void fillPictureWithNameRule(List<Picture> pictureList, String nameRule) {
        if (CollUtil.isEmpty(pictureList) || StrUtil.isBlank(nameRule)) {
            return;
        }
        long count = 1;
        try {
            for (Picture picture : pictureList) {
                String pictureName = nameRule.replaceAll("\\{序号}", String.valueOf(count++));
                picture.setName(pictureName);
            }
        } catch (Exception e) {
            log.error("图片命名规则错误: {}", nameRule);
            throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "图片命名规则错误");
        }
    }

    /**
     * 颜色搜索图片
     *
     * @param spaceId   空间 id
     * @param PicColor  图片主色调
     * @param loginUser 登录用户
     * @return 搜索到的图片列表
     */
    @Override
    public List<PictureVO> searchPictureByColor(Long spaceId, String PicColor, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "参数错误！");
        ThrowUtils.throwIf(spaceId == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        // 校验空间权限
        Space space = spaceService.getById(spaceId);
        ThrowUtils.throwIf(space == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "空间不存在");
        if (!space.getUserId().equals(loginUser.getId())) {
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ResponseCodeEnum.UNAUTHORIZED, "权限不足");
        }
        // 3. 查询包含主色调的图片
        List<Picture> pictureList = this.lambdaQuery()
                .eq(Picture::getSpaceId, spaceId)
                .isNotNull(Picture::getPicColor)
                .list();
        if (CollUtil.isEmpty(pictureList)) {
            return Collections.emptyList();
        }
        // 4. 将十六进制颜色值转换为 Color 对象
        Color targetColor = Color.decode(PicColor);
        // 5. 计算相似度并排序, 返回结果
        return pictureList.stream()
                .sorted(Comparator.comparingDouble(picture -> {
                    // 提取图片主色调
                    String hexColor = picture.getPicColor();
                    // 没有主色调, 展示在最后
                    if (StrUtil.isBlank(hexColor)) {
                        return Double.MAX_VALUE;
                    }
                    // 转换为Color对象
                    Color pictureColor = Color.decode(hexColor);
                    // 默认是从小到大排序, 但是越大的越相似, 应该排在前面, 所以取负数
                    return -ColorSimilarUtils.calculateSimilarity(targetColor, pictureColor);
                }))
                .limit(12) // 限制数量
                .toList()
                .stream().map(this::getPictureVO)
                .collect(Collectors.toList());
    }

    /**
     * 更新图片
     *
     * @param pictureUpdateRequest 图片更新请求
     * @param loginUser            登录用户
     * @return boolean 更新结果
     */
    @Override
    public boolean updatePicture(PictureUpdateRequest pictureUpdateRequest, User loginUser) {
        ThrowUtils.throwIf(pictureUpdateRequest == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        ThrowUtils.throwIf(ObjectUtil.isEmpty(loginUser), ResponseCodeEnum.UNAUTHORIZED, "权限不足");
        Picture picture = new Picture();
        BeanUtils.copyProperties(pictureUpdateRequest, picture);
        List<String> list = pictureUpdateRequest.getTags();
        String jsonStr = JSONUtil.toJsonStr(list);
        picture.setTags(jsonStr);
        // 校验
        validPicture(picture);
        // 判断是否存在
        Picture oldePicture = this.getById(pictureUpdateRequest.getId());
        ThrowUtils.throwIf(oldePicture == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "图片不存在");
        Long userId = loginUser.getId();
        if (!userId.equals(oldePicture.getUserId()) && !userService.isAdmin(loginUser)) {
            throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "权限不足");
        }
        Long spaceId = pictureUpdateRequest.getSpaceId();
        if (spaceId == null) {
            spaceId = oldePicture.getSpaceId();
        } else {
            if (ObjectUtil.notEqual(spaceId, oldePicture.getSpaceId())) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "空间不一致！");
            }
        }
        picture.setSpaceId(spaceId);
        // 填充审核参数
        this.fillReviewParams(picture, loginUser);
        // 更新
        boolean result = this.updateById(picture);
        // 更新缓存
        cacheInvalidationService.invalidatePictureListCache();
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "更新图片失败");
        return true;
    }

    /**
     * 查询空间图片的标签和分类
     *
     * @param spaceId   空间id
     * @param loginUser 登录用户
     * @return PictureTagCategory 图片标签和分类
     */
    @Override
    public PictureTagCategory listPictureTagAndCategoryBySpaceId(Long spaceId, User loginUser) {
        Long userId = loginUser.getId();
        ThrowUtils.throwIf(spaceId == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        ThrowUtils.throwIf(userId == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        Space space = spaceService.getById(spaceId);
        Long spaceUserId = space.getUserId();
        SpaceUser spaceUser = spaceUserService.getOne(new QueryWrapper<SpaceUser>().eq("space_id", spaceId).eq("user_id", userId));
        ThrowUtils.throwIf(!spaceUserId.equals(userId) && spaceUser == null, ResponseCodeEnum.UNAUTHORIZED, "权限不足！");
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("tags", "category")
                .eq("space_id", spaceId);
        List<Picture> pictures = this.list(queryWrapper);
        Set<String> tags = pictures.stream()
                .map(Picture::getTags)
                .map(e -> JSONUtil.toList(e, String.class))
                .flatMap(List::stream)
                .collect(Collectors.toSet());
        Set<String> category = pictures.stream()
                .map(Picture::getCategory)
                .collect(Collectors.toSet());
        PictureTagCategory pictureTagCategory = new PictureTagCategory();
        pictureTagCategory.setTagList(tags.stream().toList());
        pictureTagCategory.setCategoryList(category.stream().toList());
        return pictureTagCategory;
    }

    /**
     * 查询所有标签，以便手动更新标签
     *
     * @return List<String> 所有标签
     */
    @Override
    public List<String> listAllTags() {
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<Picture>().select("tags")
                .eq("review_status", PictureReviewStatusEnum.PASS.getValue())
                .isNull("space_id");
        return pictureMapper.selectObjs(queryWrapper);
    }

    /**
     * 获取图片列表(详细信息)
     * <p>
     * 使用多级缓存+减轻数据库压力
     *
     * @param pictureQueryRequest 查询条件
     * @return Page<Picture> 图片列表
     */
    @Override
    public Page<Picture> listPictureByPage(PictureQueryRequest pictureQueryRequest) {
        ThrowUtils.throwIf(pictureQueryRequest == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        Long spaceId = pictureQueryRequest.getSpaceId();
        Long userId = pictureQueryRequest.getUserId();
        User loginUser = userService.getById(userId);

        if (spaceId == null) {
            // 公共空间查询
            pictureQueryRequest.setNullSpaceId(true);
            // 只有非管理员用户才需要限制为已通过的图片
            if (loginUser == null || !userService.isAdmin(loginUser)) {
                pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            }
            // 管理员可以查看所有审核状态的图片，不设置reviewStatus
        } else {
            // 私有空间查询
            Space space = spaceService.getById(spaceId);
            SpaceUser spaceUser = spaceUserService.getOne(new QueryWrapper<SpaceUser>().eq("space_id", spaceId).eq("user_id", loginUser.getId()));
            if (!loginUser.getId().equals(space.getUserId()) && spaceUser == null) {
                throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "权限不足");
            }
            pictureQueryRequest.setUserId(null);
        }

        if (loginUser != null && userService.isAdmin(loginUser)) {
            pictureQueryRequest.setUserId(null);
            return getPicturePageByDB(pictureQueryRequest);
        }

        // 1. 构建 Key
        String jsonStr = JSONUtil.toJsonStr(pictureQueryRequest);
        String md5Str = DigestUtils.md5DigestAsHex(jsonStr.getBytes());
        final String key = "picture:listPictureByPage:" + md5Str;
        // 先查询本地缓存
        String caffeineCache = CaffeineUtil.getCache().getIfPresent(key);
        if (StrUtil.isNotBlank(caffeineCache)) {
            log.info("从本地缓存中获取数据：{}", key);
            return JSONUtil.toBean(caffeineCache, new TypeReference<>() {
            }, false);
        }
        // 本地缓存不存在查询Redis
        Page<Picture> redisCache = redisManager.getPictureCache(key);
        if (redisCache != null) {
            log.info("从Redis中获取数据：{}", key);
            CaffeineUtil.getCache().cleanUp();
            CaffeineUtil.getCache().put(key, JSONUtil.toJsonStr(redisCache));
            return redisCache;
        }
        // 查询数据库
        if (spaceId == null) {
            pictureQueryRequest.setUserId(null);
        }
        Page<Picture> dbSource = getPicturePageByDB(pictureQueryRequest);
        // 缓存数据
        CaffeineUtil.getCache().cleanUp();
        CaffeineUtil.getCache().put(key, JSONUtil.toJsonStr(dbSource));
        redisManager.deletePictureCache(key);
        redisManager.savePictureCache(key, dbSource);
        return dbSource;
    }

    /**
     * 获取图库审核状态
     *
     * @return PictureReviewCountVO，总数，待审核，审核通过，未通过
     */
    @Override
    public PictureReviewCountVO getPictureReviewCount() {
        PictureReviewCountVO result = pictureMapper.getPictureReviewCount();
        ThrowUtils.throwIf(result == null, ResponseCodeEnum.SYSTEM_ERROR, "获取图库审核状态失败");
        return result;
    }

    /**
     * 获取图片列表(数据库)
     *
     * @param pictureQueryRequest 查询条件
     * @return Page<Picture> 图片列表
     */
    private Page<Picture> getPicturePageByDB(PictureQueryRequest pictureQueryRequest) {
        // 直接查数据
        int current = pictureQueryRequest.getCurrent();
        int pageSize = pictureQueryRequest.getPageSize();
        Page<Picture> picturePage = new Page<>(current, pageSize);
        QueryWrapper<Picture> wrapper = this.getQueryWrapper(pictureQueryRequest);
        return this.page(picturePage, wrapper);
    }


    /**
     * 图片校验规则
     *
     * @param picture 图片
     */
    @Override
    public void validPicture(Picture picture) {
        ThrowUtils.throwIf(picture == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        Long pictureId = picture.getId();
        String pictureUrl = picture.getUrl();
        String introduction = picture.getIntroduction();
        ThrowUtils.throwIf(pictureId <= 0, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        ThrowUtils.throwIf(StrUtil.isNotBlank(pictureUrl) && pictureUrl.length() > 1024, ResponseCodeEnum.INVALID_PARAMETER, "参数错误：图片url长度不能超过1024个字符");
        ThrowUtils.throwIf(StrUtil.isNotBlank(introduction) && introduction.length() > 1024, ResponseCodeEnum.INVALID_PARAMETER, "参数错误：简介长度不能超过1024个字符");
    }

    /**
     * 将PictureVO转换为Picture
     *
     * @param pictureVO pictureVO
     * @return Picture
     */
    @Override
    public Picture getPicture(PictureVO pictureVO) {
        if (pictureVO == null) {
            return null;
        }
        Picture picture = new Picture();
        BeanUtils.copyProperties(pictureVO, picture);
        List<String> tagsList = pictureVO.getTags();
        String tags = JSONUtil.toJsonStr(tagsList);
        picture.setTags(tags);
        return picture;
    }

    /**
     * 将Picture转换为PictureVO
     *
     * @param picture picture
     * @return PictureVO
     */
    @Override
    public PictureVO getPictureVO(Picture picture) {
        if (picture == null) {
            return null;
        }
        PictureVO pictureVO = new PictureVO();
        BeanUtils.copyProperties(picture, pictureVO);
        String tags = picture.getTags();
        List<String> tagsList = JSONUtil.toList(tags, String.class);
        pictureVO.setTags(tagsList);
        return pictureVO;
    }

    /**
     * 上传图片
     *
     * @param t                    文件
     * @param pictureUploadRequest 上传信息
     * @param loginUser            登录用户
     * @return PictureVO PictureVO
     */
    @Override
    public <T> PictureVO uploadPicture(T t, PictureUploadRequest pictureUploadRequest, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "权限不足");
        // ADD:检验空间是否存在
        Long spaceId = pictureUploadRequest.getSpaceId();
        if (spaceId != null) {
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(ObjectUtil.isNull(space), ResponseCodeEnum.RESOURCE_NOT_FOUND, "空间不存在");
            // 仅空间主人可访问
            if (!loginUser.getId().equals(space.getUserId())) {
                throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "权限不足");
            }
            // 判断空间是否已满
            if (space.getTotalCount() > space.getMaxCount()) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "空间图片数目已满");
            }
            if (space.getTotalSize() > space.getMaxSize()) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "空间图片大小已满");
            }
        }
        // 判断是新增还是更新图片
        Long pictureId = pictureUploadRequest.getId();
        // 若是更新图片，先查看图片是否存在
        if (pictureId != null) {
            Picture oldPicture = this.getById(pictureId);
            ThrowUtils.throwIf(oldPicture == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "图片不存在");
            // 仅本人和管理员可更新
            if (!loginUser.getId().equals(oldPicture.getUserId()) && !userService.isAdmin(loginUser)) {
                throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "权限不足");
            }
        }
        // 上传图片,得到信息
        // 安装用户id划分目录
        String uploadPathPrefix;
        if (spaceId == null) {
            uploadPathPrefix = String.format("public/%s", loginUser.getId());
        } else {
            uploadPathPrefix = String.format("space/%s", spaceId);
        }
        // 上传图片
        PictureUploadTemplate template = filePictureUpload;
        if (t instanceof String) {
            template = urlPictureUpload;
        }
        UploadPictureResult uploadPictureResult = template.uploadPicture(t, uploadPathPrefix);
        // 构造入库信息
        Picture picture = Picture.builder()
                .url(uploadPictureResult.getUrl())
                .name(uploadPictureResult.getPicName())
                .picSize(uploadPictureResult.getPicSize())
                .picWidth(uploadPictureResult.getPicWidth())
                .picHeight(uploadPictureResult.getPicHeight())
                .picScale(uploadPictureResult.getPicScale())
                .picFormat(uploadPictureResult.getPicFormat())
                .userId(loginUser.getId())
                .spaceId(spaceId)
                .build();
        this.fillReviewParams(picture, loginUser);
        // 获取图片主色调
        picture.setPicColor(ColorTransformUtils.getStandardColor(uploadPictureResult.getPicColor()));
        // 如果是更新图片，则设置id
        if (pictureId != null) {
            picture.setId(pictureId);
            picture.setEditTime(LocalDateTime.now());
        }
        transactionTemplate.execute(status -> {
            boolean saved = this.saveOrUpdate(picture);
            ThrowUtils.throwIf(!saved, ResponseCodeEnum.SYSTEM_ERROR, "保存图片失败");
            if (spaceId != null) {
                boolean update = spaceService.lambdaUpdate()
                        .eq(Space::getId, spaceId)
                        .setSql("total_count = total_count + 1")
                        .setSql("total_size = total_size + " + picture.getPicSize())
                        .update();
                ThrowUtils.throwIf(!update, ResponseCodeEnum.SYSTEM_ERROR, "更新空间失败");
            }
            return true;
        });
        // 同步调用AI生成图片标签
        try {
            ImageTagsGenerateUtil.ImageTagsAndTile imageTagsAndTile = ImageTagsGenerateUtil.getTagsAndTile(picture.getUrl());
            picture.setTags(JSONUtil.toJsonStr(imageTagsAndTile.tags()));
            picture.setName(imageTagsAndTile.title());
            picture.setCategory(imageTagsAndTile.category());

            // 如果是管理员上传，则设置审核信息,自动通过审核
            if (userService.isAdmin(loginUser)) {
                fillReviewParams(picture, loginUser);
                cacheInvalidationService.invalidatePictureListCache();
            }
            // 将标签存储到Redis，每个标签增加1分
            if (spaceId != null) {
                // 只有公共空间的图片才存储标签
                if (imageTagsAndTile.tags() != null && !imageTagsAndTile.tags().isEmpty()) {
                    redisManager.incrementTagsScore(imageTagsAndTile.tags(), 1.0);
                }
            }
        } catch (Exception e) {
            // 如果调用失败，不设置Tags、Name和Category，避免阻塞主流程
            log.warn("AI生成图片标签失败，跳过设置标签、标题和分类", e);
        }
        boolean result = this.saveOrUpdate(picture);
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "上传图片失败");
        return this.getPictureVO(picture);
    }

    /**
     * 图片审核
     *
     * @param request   图片审核信息
     * @param loginUser 登录用户
     * @return 审核操作结果
     */
    @Override
    public boolean dePictureReview(PictureReviewRequest request, User loginUser) {
        // 1.参数校验
        Long id = request.getId();
        Integer reviewStatus = request.getReviewStatus();
        PictureReviewStatusEnum reviewStatusEnum = PictureReviewStatusEnum.getEnumByValue(reviewStatus);
        if (id <= 0 || reviewStatusEnum == null || reviewStatusEnum == PictureReviewStatusEnum.REVIEWING) {
            throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        }
        // 2.判断图片是否存在
        Picture oldPicture = this.getById(id);
        ThrowUtils.throwIf(oldPicture == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "图片不存在");
        // 3.不能重复审核
        ThrowUtils.throwIf(oldPicture.getReviewStatus().equals(reviewStatus), ResponseCodeEnum.SYSTEM_ERROR, "图片已审核过了！");
        // 4.执行审核
        Picture updatePicture = new Picture();
        BeanUtils.copyProperties(request, updatePicture);
        // 5.设置审核状态
        updatePicture.setReviewerId(loginUser.getId());
        updatePicture.setReviewTime(LocalDateTime.now());
        boolean result = this.updateById(updatePicture);
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "图片审核失败");

        // 如果审核通过，清除缓存
        if (reviewStatusEnum == PictureReviewStatusEnum.PASS) {
            cacheInvalidationService.invalidatePictureListCache();
        }

        // 6.返回结果
        return true;
    }

    /**
     * 填充审核参数
     *
     * @param picture   图片
     * @param loginUser 登录用户
     */
    @Override
    public void fillReviewParams(Picture picture, User loginUser) {
        ThrowUtils.throwIf(picture == null || loginUser == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        if (userService.isAdmin(loginUser)) {
            // 管理员可自动过审
            picture.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            picture.setReviewMessage("管理员自动通过");
            picture.setReviewTime(LocalDateTime.now());
        } else {
            picture.setReviewStatus(PictureReviewStatusEnum.REVIEWING.getValue());
        }
    }


    /**
     * 获取图片详细信息，包含用户信息
     *
     * @param picture picture
     * @return PictureVO
     */
    @Override
    public PictureVO getPictureVOWithUserVO(Picture picture) {
        ThrowUtils.throwIf(picture == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        PictureVO pictureVO = this.getPictureVO(picture);
        Long userId = picture.getUserId();
        if (userId != null && userId > 0) {
            User user = userService.getById(userId);
            UserVO userVO = userService.getUserVO(user);
            pictureVO.setUserVO(userVO);
        }
        return pictureVO;
    }

    /**
     * 分页获取图片的 VO (处理 UserVO)
     *
     * @param picturePage 图片的分页数据
     * @return 图片的 VO
     */
    @Override
    public Page<PictureVO> getPictureVOPage(Page<Picture> picturePage) {
        // 1.获取图片列表
        List<Picture> pictureList = picturePage.getRecords();
        // 2.封装为VO
        Page<PictureVO> pictureVOPage = new Page<>(picturePage.getCurrent(), picturePage.getSize(), picturePage.getTotal());
        if (CollUtil.isEmpty(pictureList)) {
            return pictureVOPage;
        }
        // 3.获取VO列表
        List<PictureVO> pictureVOList = pictureList.stream()
                .map(this::getPictureVO)
                .toList();
        // 4.获取用户Id集合
        Set<Long> userIdSet = pictureList.stream()
                .map(Picture::getUserId)
                .collect(Collectors.toSet());
        // 5.获取用户集合
        List<User> userList = userService.listByIds(userIdSet);
        // 6.（userId，user）分组
        Map<Long, List<User>> userMap = userList.stream()
                .collect(Collectors.groupingBy(User::getId));
        // 7. 遍历填充数据
        pictureVOList.forEach(pictureVO -> {
            Long userId = pictureVO.getUserId();
            User user = null;
            if (userMap.containsKey(userId)) {
                user = userMap.get(userId).getFirst();
            }
            UserVO userVO = userService.getUserVO(user);
            pictureVO.setUserVO(userVO);
        });
        pictureVOPage.setRecords(pictureVOList);
        return pictureVOPage;
    }

    /**
     * 根据Id获取图片全部信息 仅管理员使用
     *
     * @param id 图片id
     * @return 图片信息
     */
    @Override
    public Picture getPictureById(Long id) {
        ThrowUtils.throwIf(id == null || id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        Picture picture = this.getById(id);
        ThrowUtils.throwIf(picture == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "图片不存在");
        return picture;
    }

    /**
     * 根据Id获取图片 普通用户使用
     *
     * @param id 图片id
     * @return 图片信息
     */
    @Override
    public PictureVO getPictureVOById(Long id, User loginUser) {
        ThrowUtils.throwIf(id == null || id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        Picture picture = getPictureById(id);
        ThrowUtils.throwIf(picture == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "图片不存在");
        Long spaceId = picture.getSpaceId();
        Space space = null;
        if (spaceId != null) {
            // checkPictureAuth(picture, loginUser);
            boolean hasPermission = StpKit.SPACE.hasPermission(SpaceUserPermissionConstant.PICTURE_VIEW);
            if (!hasPermission) {
                throw new ApiException(ResponseCodeEnum.FORBIDDEN_ACCESS, "无权访问该资源");
            }
            space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "空间不存在");
        }
        List<String> permissionList = spaceUserAuthManager.getPermissionList(space, loginUser);
        picture.setPermissionList(permissionList);
        return getPictureVOWithUserVO(picture);
    }

    /**
     * 用户编辑图片
     *
     * @param pictureEditRequest 编辑图片信息请求
     * @param loginUser          当前登录用户
     * @return 是否修改成功
     */
    @Override
    public boolean editPicture(PictureEditRequest pictureEditRequest, User loginUser) {
        ThrowUtils.throwIf(pictureEditRequest == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "权限不足");
        // 1.属性拷贝
        Picture picture = new Picture();
        BeanUtils.copyProperties(pictureEditRequest, picture);
        // 2.处理tag字段
        List<String> tagList = pictureEditRequest.getTags();
        picture.setTags(JSONUtil.toJsonStr(tagList));
        // 3.设置编辑时间
        picture.setEditTime(LocalDateTime.now());
        // 4.校验合法性
        validPicture(picture);
        // 5.判断图片是否存在
        Picture oldPicture = this.getById(picture.getId());
        ThrowUtils.throwIf(oldPicture == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "图片不存在！");
        // checkPictureAuth(picture, loginUser);
        // 6.补充审核参数
        fillReviewParams(picture, loginUser);
        // 7.修改图片
        boolean result = this.updateById(picture);
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "修改图片失败！");
        return true;
    }

    /**
     * 检查图片操作权限
     *
     * @param picture   图片
     * @param loginUser 当前登录用户
     */
    @Deprecated
    public void checkPictureAuth(Picture picture, User loginUser) {
        ThrowUtils.throwIf(picture == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        Long spaceId = picture.getSpaceId();
        if (spaceId == null) {
            // 公共空间,仅本人和管理可操作
            if (!loginUser.getId().equals(picture.getUserId()) && !userService.isAdmin(loginUser)) {
                throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "权限不足");
            } else {
                // 私有空间,仅本人可操作
                if (!loginUser.getId().equals(picture.getUserId())) {
                    throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "权限不足");
                }
            }
        }

    }

    /**
     * 封装图片的分页查询条件
     *
     * @param request 查询参数
     * @return 查询条件
     */
    @Override
    public QueryWrapper<Picture> getQueryWrapper(PictureQueryRequest request) {
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        if (request == null) {
            return wrapper;
        }
        // 1. 获取查询参数
        Long id = request.getId();
        String name = request.getName();
        String introduction = request.getIntroduction();
        String category = request.getCategory();
        List<String> tags = request.getTags(); // 单独处理
        Long picSize = request.getPicSize();
        Integer picWidth = request.getPicWidth();
        Integer picHeight = request.getPicHeight();
        Double picScale = request.getPicScale();
        String picFormat = request.getPicFormat();
        String searchText = request.getSearchText(); // 单独处理
        Long userId = request.getUserId();
        Long spaceId = request.getSpaceId();
        boolean nullSpaceId = request.isNullSpaceId();
        Integer reviewStatus = request.getReviewStatus();
        String reviewMessage = request.getReviewMessage();
        Long reviewerId = request.getReviewerId();
        LocalDateTime startEditTime = request.getStartEditTime();
        LocalDateTime endEditTime = request.getEndEditTime();
        String sortField = request.getSortField();
        String sortOrder = request.getSortOrder();
        // 2. 封装查询条件
        // 修复：只有当id不为null且大于0时才添加id条件，避免id=0被忽略的问题
        wrapper.eq(id != null && id > 0, "id", id);
        wrapper.like(StrUtil.isNotBlank(name), "name", name);
        wrapper.like(StrUtil.isNotBlank(introduction), "introduction", introduction);
        wrapper.eq(StrUtil.isNotBlank(category), "category", category);
        // 修复：对于数值类型，只有当值不为null且不为0时才添加条件（0通常表示不筛选）
        wrapper.eq(picSize != null && picSize > 0, "pic_size", picSize);
        wrapper.eq(picWidth != null && picWidth > 0, "pic_width", picWidth);
        wrapper.eq(picHeight != null && picHeight > 0, "pic_height", picHeight);
        wrapper.eq(picScale != null && picScale > 0, "pic_scale", picScale);
        wrapper.like(StrUtil.isNotBlank(picFormat), "pic_format", picFormat);
        // 修复：只有当userId不为null且大于0时才添加userId条件
        wrapper.eq(userId != null && userId > 0, "user_id", userId);
        // 修复：reviewStatus可以为0（待审核状态），所以只判断不为null
        wrapper.eq(reviewStatus != null, "review_status", reviewStatus);
        wrapper.like(StrUtil.isNotBlank(reviewMessage), "review_message", reviewMessage);
        wrapper.eq(reviewerId != null && reviewerId > 0, "reviewer_id", reviewerId);
        wrapper.ge(startEditTime != null, "edit_time", startEditTime);
        wrapper.lt(endEditTime != null, "edit_time", endEditTime);

        // spaceId的处理逻辑，避免重复判断
        if (nullSpaceId) {
            // 如果明确要求查询spaceId为null的记录（公共图片）
            wrapper.isNull("space_id");
        } else if (spaceId != null && spaceId > 0) {
            // 如果指定了具体的spaceId
            wrapper.eq("space_id", spaceId);
        }
        // 如果nullSpaceId=false且spaceId<=0，则不添加space_id相关的查询条件

        // tags 单独处理, 按 "标签1" 搜索
        if (CollUtil.isNotEmpty(tags)) {
            for (String tag : tags) {
                wrapper.like("tags", "\"" + tag + "\"");
            }
        }
        // 名称和简介可以同时搜
        if (StrUtil.isNotBlank(searchText)) {
            // where (name like '%searchText%' or introduction like '%searchText%') and isDelete = 0;
            wrapper.and(w -> w.like("name", searchText)
                    .or()
                    .like("introduction", searchText));
        }
        // 排序
        if (StrUtil.isNotBlank(sortField)) {
            boolean isAsc = "ascend".equals(sortOrder);
            wrapper.orderBy(true, isAsc, sortField);
        }
        return wrapper;
    }

    /**
     * 批量上传图片
     *
     * @param files              文件列表
     * @param batchUploadRequest 批量上传请求
     * @param loginUser          登录用户
     * @return 批量上传结果
     */
    @Override
    public PictureBatchUploadVO batchUploadPictures(MultipartFile[] files, PictureBatchUploadRequest batchUploadRequest, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "权限不足");
        ThrowUtils.throwIf(files == null || files.length == 0, ResponseCodeEnum.INVALID_PARAMETER, "上传文件不能为空");
        ThrowUtils.throwIf(files.length > 20, ResponseCodeEnum.INVALID_PARAMETER, "批量上传文件数量不能超过20个");
        // ADD:检验空间是否存在
        Long spaceId = batchUploadRequest.getSpaceId();
        Space space;
        if (spaceId != null) {
            space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(ObjectUtil.isNull(space), ResponseCodeEnum.RESOURCE_NOT_FOUND, "空间不存在");
            // 仅空间主人可访问
            if (!loginUser.getId().equals(space.getUserId())) {
                throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "权限不足");
            }
        }

        // 预先计算所有文件的总大小，用于空间配额验证
        long totalUploadSize = 0L;
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                totalUploadSize += file.getSize();
            }
        }

        // 检查空间配额
        if (spaceId != null) {
            boolean hasQuota = spaceService.checkSpaceQuota(spaceId, files.length, totalUploadSize);
            if (!hasQuota) {
                long[] remainingQuota = spaceService.getSpaceRemainingQuota(spaceId);
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER,
                        String.format("空间配额不足！剩余可上传图片数量：%d，剩余可用空间大小：%d字节",
                                remainingQuota[0], remainingQuota[1]));
            }
        }

        PictureBatchUploadVO result = new PictureBatchUploadVO();
        result.setTotalCount(files.length);
        result.setSuccessCount(0);
        result.setFailureCount(0);
        result.setSuccessList(new ArrayList<>());
        result.setFailureList(new ArrayList<>());
        result.setHasAsyncTask(false);

        // 判断用户角色，设置审核状态
        boolean isAdmin = UserRoleEnum.ADMIN.getValue().equals(loginUser.getUserRole());

        // 划分目录
        String uploadPathPrefix;
        if (spaceId == null) {
            uploadPathPrefix = String.format("public/%s", loginUser.getId());
        } else {
            uploadPathPrefix = String.format("space/%s", spaceId);
        }

        for (MultipartFile file : files) {
            try {
                // 验证单个文件
                if (file.isEmpty()) {
                    addFailureInfo(result, file.getOriginalFilename(), "文件为空", file.getSize());
                    continue;
                }

                // 上传图片到COS
                UploadPictureResult uploadPictureResult = filePictureUpload.uploadPicture(file, uploadPathPrefix);

                // 构造图片信息
                Picture picture = buildPictureFromRequest(uploadPictureResult, batchUploadRequest, loginUser, isAdmin);
                // 处理图片主色调
                picture.setPicColor(ColorTransformUtils.getStandardColor(uploadPictureResult.getPicColor()));
                // 保存到数据库
                String pictureName = picture.getName();
                if (pictureName.length() > 100) {
                    pictureName = pictureName.substring(0, 100);
                    picture.setName(pictureName);
                }
                // 管理员自动填写审核参数
                if (isAdmin) {
                    fillReviewParams(picture, loginUser);
                }
                boolean saved = this.save(picture);
                if (!saved) {
                    addFailureInfo(result, file.getOriginalFilename(), "保存到数据库失败", file.getSize());
                    continue;
                }

                // 更新空间统计信息
                if (spaceId != null) {
                    boolean updateSpace = spaceService.lambdaUpdate()
                            .eq(Space::getId, spaceId)
                            .setSql("total_count = total_count + 1")
                            .setSql("total_size = total_size + " + picture.getPicSize())
                            .update();
                    if (!updateSpace) {
                        log.warn("更新空间统计信息失败，spaceId: {}, pictureId: {}", spaceId, picture.getId());
                    }
                }

                // 处理AI标签生成
                handleAiProcessing(picture, batchUploadRequest, result, loginUser.getId());

                // 添加到成功列表
                result.getSuccessList().add(this.getPictureVO(picture));
                result.setSuccessCount(result.getSuccessCount() + 1);

            } catch (Exception e) {
                log.error("批量上传单个文件失败: {}", file.getOriginalFilename(), e);
                addFailureInfo(result, file.getOriginalFilename(), e.getMessage(), file.getSize());
            }
        }

        result.setFailureCount(result.getTotalCount() - result.getSuccessCount());

        // 如果是管理员批量上传且有成功上传的图片，清除缓存
        if (isAdmin && result.getSuccessCount() > 0) {
            cacheInvalidationService.invalidatePictureListCache();
        }
        // 如果是空间批量上传且有成功上传的图片，清除缓存
        if (uploadPathPrefix.startsWith("space")) {
            cacheInvalidationService.invalidatePictureListCache();
        }

        return result;
    }

    /**
     * 根据请求构建Picture对象
     */
    private Picture buildPictureFromRequest(UploadPictureResult uploadResult, PictureBatchUploadRequest request, User loginUser, boolean isAdmin) {
        Picture picture = Picture.builder()
                .url(uploadResult.getUrl())
                .picSize(uploadResult.getPicSize())
                .picWidth(uploadResult.getPicWidth())
                .picHeight(uploadResult.getPicHeight())
                .picScale(uploadResult.getPicScale())
                .picFormat(uploadResult.getPicFormat())
                .userId(loginUser.getId())
                .spaceId(request.getSpaceId())
                .build();

        // 设置审核状态
        if (isAdmin) {
            picture.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            picture.setReviewerId(loginUser.getId());
            picture.setReviewTime(LocalDateTime.now());
        } else {
            picture.setReviewStatus(PictureReviewStatusEnum.REVIEWING.getValue());
        }

        // 处理图片名称
        handlePictureName(picture, uploadResult, request);

        // 处理标签
        handlePictureTags(picture, request);

        // 处理分类
        handlePictureCategory(picture, request);

        return picture;
    }

    /**
     * 处理图片名称
     */
    private void handlePictureName(Picture picture, UploadPictureResult uploadResult, PictureBatchUploadRequest request) {
        String nameStrategy = request.getNameStrategy();
        switch (nameStrategy) {
            case "custom":
                if (StrUtil.isNotBlank(request.getNamePrefix())) {
                    picture.setName(request.getNamePrefix() + "_" + System.currentTimeMillis());
                } else {
                    picture.setName(uploadResult.getPicName());
                }
                break;
            case "filename":
                picture.setName(uploadResult.getPicName());
                break;
            case "auto":
            default:
                // AI生成或使用文件名，暂时使用文件名，AI生成在异步处理中完成
                picture.setName(uploadResult.getPicName());
                break;
        }
    }

    /**
     * 处理图片标签
     */
    private void handlePictureTags(Picture picture, PictureBatchUploadRequest request) {
        String tagStrategy = request.getTagStrategy();
        switch (tagStrategy) {
            case "custom":
                if (CollUtil.isNotEmpty(request.getCustomTags())) {
                    picture.setTags(JSONUtil.toJsonStr(request.getCustomTags()));
                    // 将自定义标签存储到Redis
                    redisManager.incrementTagsScore(request.getCustomTags(), 1.0);
                }
                break;
            case "none":
                picture.setTags("[]");
                break;
            case "ai":
            default:
                // AI生成标签，在异步处理中完成
                picture.setTags("[]");
                break;
        }
    }

    /**
     * 处理图片分类
     */
    private void handlePictureCategory(Picture picture, PictureBatchUploadRequest request) {
        String categoryStrategy = request.getCategoryStrategy();
        switch (categoryStrategy) {
            case "custom":
                if (StrUtil.isNotBlank(request.getCustomCategory())) {
                    picture.setCategory(request.getCustomCategory());
                }
                break;
            case "none":
                // 不设置分类
                break;
            case "ai":
            default:
                // AI生成分类，在异步处理中完成
                break;
        }
    }

    /**
     * 处理AI处理逻辑
     */
    private void handleAiProcessing(Picture picture, PictureBatchUploadRequest request, PictureBatchUploadVO result, Long userId) {
        boolean needAiProcess = "ai".equals(request.getTagStrategy()) || "ai".equals(request.getCategoryStrategy());

        if (needAiProcess && request.getAsyncAiProcess()) {
            // 异步处理AI标签生成
            asyncAiProcessService.processAiTagsAndCategory(picture.getId(), picture.getUrl(), "auto".equals(request.getNameStrategy()), userId);
            result.setHasAsyncTask(true);
        } else if (needAiProcess) {
            // 同步处理AI标签生成（不推荐，会很慢）
            log.warn("检测到同步AI处理请求，这会显著增加响应时间，建议使用异步处理");
            try {
                ImageTagsGenerateUtil.ImageTagsAndTile imageTagsAndTile = ImageTagsGenerateUtil.getTagsAndTile(picture.getUrl());

                if ("ai".equals(request.getTagStrategy()) && imageTagsAndTile.tags() != null) {
                    picture.setTags(JSONUtil.toJsonStr(imageTagsAndTile.tags()));
                    redisManager.incrementTagsScore(imageTagsAndTile.tags(), 1.0);
                }

                if ("ai".equals(request.getCategoryStrategy()) && StrUtil.isNotBlank(imageTagsAndTile.category())) {
                    picture.setCategory(imageTagsAndTile.category());
                }

                if ("auto".equals(request.getNameStrategy()) && StrUtil.isNotBlank(imageTagsAndTile.title())) {
                    picture.setName(imageTagsAndTile.title());
                }

                // 更新数据库
                this.updateById(picture);
            } catch (Exception e) {
                log.warn("同步处理AI标签失败，图片ID: {}", picture.getId(), e);
            }
        }
    }

    /**
     * 添加失败信息
     */
    private void addFailureInfo(PictureBatchUploadVO result, String fileName, String reason, Long fileSize) {
        PictureBatchUploadVO.UploadFailureInfo failureInfo = new PictureBatchUploadVO.UploadFailureInfo();
        failureInfo.setFileName(fileName);
        failureInfo.setFailureReason(reason);
        failureInfo.setFileSize(fileSize);
        result.getFailureList().add(failureInfo);
    }
}
